/**
 * 分析UT中Mock类的组织方式
 * 
 * 分析：
 * 1. Mock成员变量定义在哪里（.h的public/protected/private？还是.cpp开头？）
 * 2. Mock类头文件命名规范
 * 3. SetUp中如何初始化Mock
 * 4. 测试函数中如何使用Mock
 */

const fs = require('fs');
const path = require('path');

const stats = {
    totalTestFiles: 0,
    testFilesWithMocks: 0,
    
    // Mock成员变量定义位置
    mockMemberLocation: {
        inHeaderProtected: 0,      // .h文件的protected部分
        inHeaderPrivate: 0,         // .h文件的private部分
        inHeaderPublic: 0,          // .h文件的public部分
        inCppBeforeClass: 0,        // .cpp文件类定义前
        inCppClass: 0,              // .cpp文件类定义中
    },
    
    // Mock类头文件命名
    mockHeaderNaming: {
        mock_prefix: 0,             // mock_xxx.h
        xxx_mock: 0,                // xxx_mock.h
        xxx_mock_impl: 0,           // xxx_mock_impl.h
        xxx_impl_mock: 0,           // xxx_impl_mock.h
        other: 0
    },
    
    // SetUp初始化模式
    setupPatterns: {
        makeShared: 0,              // std::make_shared<MockXxx>()
        newOperator: 0,             // new MockXxx()
        sptrMakeSptr: 0,            // sptr<MockXxx>::MakeSptr()
    },
    
    // 测试函数使用模式
    usagePatterns: {
        memberPointer: 0,           // mockXxx_->Method()
        memberRef: 0,               // mockXxx_.Method()
        expectCallDeref: 0,         // EXPECT_CALL(*mockXxx_, ...)
    }
};

const examples = {
    headerWithMockMembers: [],
    cppWithSetUp: [],
    mockHeaderIncludes: []
};

/**
 * 查找测试文件及其头文件
 */
function findTestFilesPaired(dir, maxDepth = 10, currentDepth = 0) {
    const pairs = [];
    
    if (currentDepth > maxDepth) return pairs;
    
    try {
        const items = fs.readdirSync(dir, { withFileTypes: true });
        
        for (const item of items) {
            if (!item.isDirectory()) {
                if (item.name.endsWith('_test.cpp') || item.name.endsWith('test.cpp')) {
                    const cppPath = path.join(dir, item.name);
                    
                    // 尝试找到对应的.h文件
                    const baseName = item.name.replace('.cpp', '');
                    const hPath = path.join(dir, baseName + '.h');
                    
                    // 也可能在include目录
                    const includeDir = path.join(path.dirname(dir), 'include');
                    const hPathInInclude = path.join(includeDir, baseName + '.h');
                    
                    pairs.push({
                        cpp: cppPath,
                        h: fs.existsSync(hPath) ? hPath : 
                           (fs.existsSync(hPathInInclude) ? hPathInInclude : null)
                    });
                }
                continue;
            }
            
            const fullPath = path.join(dir, item.name);
            
            if (item.name.includes('node_modules') || 
                item.name.includes('.git') ||
                item.name.includes('out') ||
                item.name.includes('build')) {
                continue;
            }
            
            const subPairs = findTestFilesPaired(fullPath, maxDepth, currentDepth + 1);
            pairs.push(...subPairs);
        }
    } catch (err) {
        // Ignore
    }
    
    return pairs;
}

/**
 * 分析头文件中的Mock成员变量
 */
function analyzeHeaderFile(hPath) {
    try {
        const content = fs.readFileSync(hPath, 'utf-8');
        
        // 检测Mock成员变量
        const hasMockMembers = /Mock\w+\s*\*/.test(content) || 
                              /std::shared_ptr<Mock\w+>/.test(content) ||
                              /sptr<Mock\w+>/.test(content);
        
        if (!hasMockMembers) return null;
        
        // 确定位置
        const protectedMatch = content.match(/protected:([\s\S]*?)(public:|private:|$)/);
        const privateMatch = content.match(/private:([\s\S]*?)(public:|protected:|$)/);
        const publicMatch = content.match(/public:([\s\S]*?)(protected:|private:|$)/);
        
        let location = 'unknown';
        
        if (protectedMatch && /Mock\w+/.test(protectedMatch[1])) {
            location = 'protected';
            stats.mockMemberLocation.inHeaderProtected++;
        } else if (privateMatch && /Mock\w+/.test(privateMatch[1])) {
            location = 'private';
            stats.mockMemberLocation.inHeaderPrivate++;
        } else if (publicMatch && /Mock\w+/.test(publicMatch[1])) {
            location = 'public';
            stats.mockMemberLocation.inHeaderPublic++;
        }
        
        return {
            path: hPath,
            location,
            snippet: content.substring(0, 500)
        };
    } catch (err) {
        return null;
    }
}

/**
 * 分析cpp文件中的Mock使用
 */
function analyzeCppFile(cppPath) {
    try {
        const content = fs.readFileSync(cppPath, 'utf-8');
        
        // 检测Mock类头文件包含
        const mockIncludes = [];
        const includeRegex = /#include\s+["<]([^">]*mock[^">]*\.h)[">]/gi;
        let match;
        while ((match = includeRegex.exec(content)) !== null) {
            mockIncludes.push(match[1]);
            
            // 分析命名模式
            const fileName = path.basename(match[1]);
            if (fileName.startsWith('mock_')) stats.mockHeaderNaming.mock_prefix++;
            else if (fileName.endsWith('_mock.h')) stats.mockHeaderNaming.xxx_mock++;
            else if (fileName.includes('_mock_impl')) stats.mockHeaderNaming.xxx_mock_impl++;
            else if (fileName.includes('_impl_mock')) stats.mockHeaderNaming.xxx_impl_mock++;
            else stats.mockHeaderNaming.other++;
        }
        
        if (mockIncludes.length === 0) return null;
        
        stats.testFilesWithMocks++;
        
        // 检测SetUp中的初始化
        const setupMatch = content.match(/void\s+\w+::SetUp\s*\([^)]*\)\s*\{([^}]{0,2000})\}/);
        if (setupMatch) {
            const setupBody = setupMatch[1];
            
            if (/std::make_shared<Mock\w+>/.test(setupBody)) {
                stats.setupPatterns.makeShared++;
            }
            if (/new\s+Mock\w+/.test(setupBody)) {
                stats.setupPatterns.newOperator++;
            }
            if (/sptr<Mock\w+>::MakeSptr/.test(setupBody)) {
                stats.setupPatterns.sptrMakeSptr++;
            }
        }
        
        // 检测测试函数中的使用
        if (/\w+_->/.test(content)) stats.usagePatterns.memberPointer++;
        if (/EXPECT_CALL\s*\(\s*\*\w+_/.test(content)) stats.usagePatterns.expectCallDeref++;
        
        return {
            path: cppPath,
            mockIncludes,
            hasSetUp: setupMatch !== null
        };
    } catch (err) {
        return null;
    }
}

/**
 * 主函数
 */
function main() {
    console.log('🔍 开始分析Mock组织方式...\n');
    
    const ohCodePath = path.join(__dirname, '../OHCode');
    
    if (!fs.existsSync(ohCodePath)) {
        console.error('❌ OHCode目录不存在！');
        process.exit(1);
    }
    
    console.log('📂 查找测试文件对（cpp+h）...');
    const testPairs = findTestFilesPaired(ohCodePath);
    stats.totalTestFiles = testPairs.length;
    
    console.log(`✅ 找到 ${testPairs.length} 个测试文件\n`);
    console.log('📊 开始分析...\n');
    
    let processed = 0;
    const progressInterval = Math.max(1, Math.floor(testPairs.length / 20));
    
    for (const pair of testPairs) {
        // 分析头文件
        if (pair.h) {
            const headerResult = analyzeHeaderFile(pair.h);
            if (headerResult && examples.headerWithMockMembers.length < 3) {
                examples.headerWithMockMembers.push(headerResult);
            }
        }
        
        // 分析cpp文件
        const cppResult = analyzeCppFile(pair.cpp);
        if (cppResult) {
            if (cppResult.mockIncludes.length > 0 && examples.mockHeaderIncludes.length < 5) {
                examples.mockHeaderIncludes.push(cppResult.mockIncludes);
            }
            if (cppResult.hasSetUp && examples.cppWithSetUp.length < 3) {
                examples.cppWithSetUp.push(cppResult);
            }
        }
        
        processed++;
        if (processed % progressInterval === 0 || processed === testPairs.length) {
            const percent = ((processed / testPairs.length) * 100).toFixed(1);
            console.log(`  进度: ${processed}/${testPairs.length} (${percent}%)`);
        }
    }
    
    console.log('\n✅ 分析完成！\n');
    
    // 生成报告
    const report = {
        summary: {
            totalTestFiles: stats.totalTestFiles,
            testFilesWithMocks: stats.testFilesWithMocks,
            mockUsagePercentage: ((stats.testFilesWithMocks / stats.totalTestFiles) * 100).toFixed(2) + '%'
        },
        mockMemberLocation: stats.mockMemberLocation,
        mockHeaderNaming: stats.mockHeaderNaming,
        setupPatterns: stats.setupPatterns,
        usagePatterns: stats.usagePatterns,
        examples
    };
    
    const reportPath = path.join(__dirname, '../MOCK_ORGANIZATION_ANALYSIS.json');
    fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
    
    console.log(`✅ 详细报告已保存: ${reportPath}\n`);
    
    // 打印摘要
    console.log('━'.repeat(80));
    console.log('                   📊 Mock组织方式分析');
    console.log('━'.repeat(80));
    console.log();
    
    console.log(`总测试文件: ${report.summary.totalTestFiles}`);
    console.log(`使用Mock的文件: ${report.summary.testFilesWithMocks} (${report.summary.mockUsagePercentage})\n`);
    
    console.log('1️⃣ Mock成员变量定义位置:');
    console.log(`  - .h文件protected: ${stats.mockMemberLocation.inHeaderProtected}`);
    console.log(`  - .h文件private: ${stats.mockMemberLocation.inHeaderPrivate}`);
    console.log(`  - .h文件public: ${stats.mockMemberLocation.inHeaderPublic}`);
    console.log(`  - .cpp文件: ${stats.mockMemberLocation.inCppClass + stats.mockMemberLocation.inCppBeforeClass}\n`);
    
    console.log('2️⃣ Mock头文件命名规范:');
    console.log(`  - mock_xxx.h: ${stats.mockHeaderNaming.mock_prefix}`);
    console.log(`  - xxx_mock.h: ${stats.mockHeaderNaming.xxx_mock}`);
    console.log(`  - xxx_mock_impl.h: ${stats.mockHeaderNaming.xxx_mock_impl}`);
    console.log(`  - xxx_impl_mock.h: ${stats.mockHeaderNaming.xxx_impl_mock}`);
    console.log(`  - 其他: ${stats.mockHeaderNaming.other}\n`);
    
    console.log('3️⃣ SetUp初始化模式:');
    console.log(`  - std::make_shared: ${stats.setupPatterns.makeShared}`);
    console.log(`  - new operator: ${stats.setupPatterns.newOperator}`);
    console.log(`  - sptr::MakeSptr: ${stats.setupPatterns.sptrMakeSptr}\n`);
    
    console.log('4️⃣ Mock使用模式:');
    console.log(`  - memberPtr->: ${stats.usagePatterns.memberPointer}`);
    console.log(`  - EXPECT_CALL(*memberPtr_): ${stats.usagePatterns.expectCallDeref}\n`);
    
    console.log('━'.repeat(80));
    console.log();
    
    // 打印示例
    if (examples.mockHeaderIncludes.length > 0) {
        console.log('📝 Mock头文件包含示例：');
        for (let i = 0; i < Math.min(3, examples.mockHeaderIncludes.length); i++) {
            console.log(`  ${i + 1}. ${examples.mockHeaderIncludes[i].join(', ')}`);
        }
        console.log();
    }
}

// 运行
main();

